package com.zyr.config;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zyr.utils.JwtUtils;
import com.zyr.constraint.AuthConstants;
import com.zyr.constraint.BusinessEnum;
import com.zyr.constraint.HttpConstants;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import com.zyr.model.Result;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.time.Instant;

/**
 * @author 张雨润
 * @date 2024/7/26 下午7:43
 * @Description 全局Token过滤器，约定令牌存放位置请求头 Authorization 值格式： bearer token
 */
@Slf4j
@Component
public class AuthFilter implements GlobalFilter, Ordered {
    @Resource
    WhiteUrlConfig whiteUrlConfig;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    /**
     * 校验token
     * 1.获取请求
     * 2.判断白名单路径
     *      ·放行
     *      ·不放行，身份认证
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getPath().toString();
        if(whiteUrlConfig.getAllowUrl().contains(path)){
            // 在白名单内，放行
            return chain.filter(exchange);
        }
        // 从约定位置获取 Authorization，值格式: bearer token
        String authorizationValue = request.getHeaders().getFirst(AuthConstants.AUTHORIZATION);
        if(StringUtils.hasText(authorizationValue)){
            //从Authorization获取token,消除前缀 bearer
            String tokenValue = authorizationValue.replaceFirst(AuthConstants.BEARER,"");
            // 验证token加密比对
            if (!JwtUtils.verify(tokenValue)) {
                log.info("非法的token");
            }
            // 如果token有值，并且redis中存在
            if (StringUtils.hasText(tokenValue) && Boolean.TRUE.equals(stringRedisTemplate.hasKey(AuthConstants.LOGIN_TOKEN_PREFIX + tokenValue))) {
                //身份验证通过，放行
                return chain.filter(exchange);
            }
        }
        // 流程如果走到这，说明身份验证失败,返回响应结果
        log.error("拦截非法请求:时间:{}，请求API路径:{}", Instant.now(),path);
        ServerHttpResponse response = exchange.getResponse();
        response.getHeaders().set(HttpConstants.CONTENT_TYPE,HttpConstants.application_json);
        // 响应消息
        Result<Object> result = Result.error(BusinessEnum.UN_AUTHORIZATION);
        // 创建ObjectMapper对象,用于JSON序列化和反序列化
        ObjectMapper objectMapper = new ObjectMapper();
        byte[] bytes;
        try {
            // 转化为JSON字节码
            bytes = objectMapper.writeValueAsBytes(result);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        // 缓冲封装
        DataBuffer dataBUffer = response.bufferFactory().wrap(bytes);
        return response.writeWith(Mono.just(dataBUffer));
    }

    /**
     * 保证最先经过的过滤器
     * @return
     */
    @Override
    public int getOrder() {
        return -5;
    }
}
